﻿
Imports SlimDX
Imports SlimDX.Direct3D9

Public Class ShaderChicago
    Implements IShader
    'Chicago Variables
    Public Maps() As MapBlock
    Dim Flags, firstMapType, framebufferBlendFunction As Short
    Sub New(ByVal schiTag As Magic.Core.Tag)

        AddHandler schiTag.TagHasChanged, AddressOf Changed
        Dim MapBlock As Array = schiTag("maps")
        Dim MapCount As Integer = MapBlock.GetLength(0)
        Flags = schiTag(13)
        firstMapType = schiTag(14)
        framebufferBlendFunction = schiTag(15)
        ReDim Maps(MapCount - 1)
        For x As Integer = 0 To MapCount - 1
            Maps(x) = New MapBlock(x, MapBlock)
        Next
    End Sub
    Sub Changed(ByVal schiTag As Magic.Core.Tag)
        Dim MapBlock As Array = schiTag("maps")
        Dim MapCount As Integer = MapBlock.GetLength(0)
        Flags = schiTag(13)
        firstMapType = schiTag(14)
        framebufferBlendFunction = schiTag(15)
        ReDim Maps(MapCount - 1)
        For x As Integer = 0 To MapCount - 1
            Maps(x) = New MapBlock(x, MapBlock)
        Next
    End Sub
    Protected Function FramebufferFunction(ByVal tFunction As Short, ByRef inverse As Boolean) As TextureOperation
        inverse = False
        Select Case tFunction
            Case 0
                Return TextureOperation.SelectArg2
            Case 1
                Return TextureOperation.SelectArg1
            Case 2
                Return TextureOperation.Modulate
            Case 3
                Return TextureOperation.Modulate2X
            Case 4
                Return TextureOperation.Add
            Case 5
                Return TextureOperation.AddSigned
            Case 6
                Return TextureOperation.AddSigned2X
            Case 7
                Return TextureOperation.Subtract
            Case 8
                inverse = True
                Return TextureOperation.Subtract
            Case 9
                Return TextureOperation.BlendCurrentAlpha
            Case 10
                inverse = True
                Return TextureOperation.BlendCurrentAlpha
            Case 11
                Return TextureOperation.BlendTextureAlpha
            Case 12
                inverse = True
                Return TextureOperation.BlendTextureAlpha
            Case Else
                Return TextureOperation.Modulate
        End Select
    End Function 'FramebufferFunction
    Public Structure MapBlock
        Public flags As Short    ' unfiltered, alpha replicate, u-clamped, v-clamped
        Public colorFunction As Short    ' current, next map, multiply, double-multiply, add, add-signed, add-signed next map, subtract current, subtract next map, blend current alpha, blend current alpha-inverse, blend next map alpha, blend next map alpha-inverse
        Public alphaFunction As Short    ' current, next map, multiply, double-multiply, add, add-signed, add-signed next map, subtract current, subtract next map, blend current alpha, blend current alpha-inverse, blend next map alpha, blend next map alpha-inverse
        Public mapUScale As Single
        Public mapVScale As Single
        Public mapUOffset As Single
        Public mapVOffset As Single
        Public mapRotation As Single
        Public mipMapBias As Single
        Public map As Texture
        Public uAnimationSource As Short    ' none, A out, B out, C out, D out
        Public uAnimationFunction As Short    ' one, zero, cosine, cosine (variable period), diagonal wave, diagonal wave (variable period), slide, slide (variable period), noise, jitter, wander, spark
        Public uAnimationPeriod As Single
        Public uAnimationPhase As Single
        Public uAnimationScale As Single
        Public vAnimationSource As Short    ' none, A out, B out, C out, D out
        Public vAnimationFunction As Short    ' one, zero, cosine, cosine (variable period), diagonal wave, diagonal wave (variable period), slide, slide (variable period), noise, jitter, wander, spark
        Public vAnimationPeriod As Single
        Public vAnimationPhase As Single
        Public vAnimationScale As Single
        Public rotAnimationSource As Short  ' none, A out, B out, C out, D out
        Public rotAnimationFunction As Short   ' one, zero, cosine, cosine (variable period), diagonal wave, diagonal wave (variable period), slide, slide (variable period), noise, jitter, wander, spark
        Public rotAnimationPeriod As Single
        Public rotAnimationPhase As Single
        Public rotAnimationScale As Single
        Public rotAnimationCenter As Vector2
        Public Sub New(ByVal Index As Integer, ByVal tagArray As Array)
            flags = tagArray.GetValue(Index, 0)
            colorFunction = tagArray.GetValue(Index, 3)
            alphaFunction = tagArray.GetValue(Index, 4)
            mapUScale = tagArray.GetValue(Index, 6)
            mapVScale = tagArray.GetValue(Index, 7)
            mapUOffset = tagArray.GetValue(Index, 8)
            mapVOffset = tagArray.GetValue(Index, 9)
            mapRotation = tagArray.GetValue(Index, 10)
            mipMapBias = tagArray.GetValue(Index, 11)

            Dim mapIdent As Integer = tagArray.GetValue(Index, 12)
            If mapIdent > -1 Then

                map = New Bitmap(magicMap.Library(mapIdent)).Texture
            Else
                map = Globals.default2d(IShader.DefaultTextures.Additive)
            End If
            uAnimationSource = tagArray.GetValue(Index, 15)
            uAnimationFunction = tagArray.GetValue(Index, 16)
            uAnimationPeriod = tagArray.GetValue(Index, 17)
            uAnimationPhase = tagArray.GetValue(Index, 18)
            uAnimationScale = tagArray.GetValue(Index, 19)
            vAnimationSource = tagArray.GetValue(Index, 20)
            vAnimationFunction = tagArray.GetValue(Index, 21)
            vAnimationPeriod = tagArray.GetValue(Index, 22)
            vAnimationPhase = tagArray.GetValue(Index, 23)
            vAnimationScale = tagArray.GetValue(Index, 24)
            rotAnimationSource = tagArray.GetValue(Index, 25)
            rotAnimationFunction = tagArray.GetValue(Index, 26)
            rotAnimationPeriod = tagArray.GetValue(Index, 27)
            rotAnimationPhase = tagArray.GetValue(Index, 28)
            rotAnimationScale = tagArray.GetValue(Index, 29)
            rotAnimationCenter = New Vector2(tagArray.GetValue(Index, 30)(0), tagArray.GetValue(Index, 30)(1))

        End Sub 'Read 
    End Structure 'MapBlock
    Private Sub SetFramebufferFunction(ByVal [function] As Short)
        Select Case [function]
            Case 0 ': // alpha blend
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Add)
                xDevice.SetRenderState(RenderState.BlendOperationAlpha, BlendOperation.Add)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha)
                xDevice.SetRenderState(RenderState.SourceBlendAlpha, Blend.Zero)
                xDevice.SetRenderState(RenderState.DestinationBlendAlpha, Blend.Zero)
            Case 1, 2 ': // multiply
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Add)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceColor)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.DestinationColor)
            Case 3 ': // add
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Add)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.One)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.One)
            Case 4 ': // subtract
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Subtract)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.One)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.One)
            Case 5 ': // component min
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Minimum)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.One)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.One)
            Case 6 ': // component max
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Maximum)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.One)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.One)
            Case 7 ': // alpha-multiply add
                xDevice.SetRenderState(RenderState.BlendOperation, BlendOperation.Add)
                xDevice.SetRenderState(RenderState.SourceBlend, Blend.SourceAlpha)
                xDevice.SetRenderState(RenderState.DestinationBlend, Blend.DestinationAlpha)
        End Select
    End Sub
    Public Overloads Sub BeginPass(ByVal pass As Integer) Implements IShader.BeginPass
        'shaderEffect.BeginPass(pass)
        If pass = 0 Then
            Dim inverseColor As Boolean = False
            Dim inverseAlpha As Boolean = False

            'Dim tPixel As PixelShader = xDevice.PixelShader
            'Dim tVertex As VertexShader = xDevice.VertexShader


            xDevice.PixelShader = Nothing
            xDevice.VertexShader = Nothing

            xDevice.SetTextureStageState(0, TextureStage.ColorOperation, TextureOperation.SelectArg1)
            xDevice.SetTextureStageState(0, TextureStage.AlphaOperation, TextureOperation.SelectArg1)
            xDevice.SetRenderState(RenderState.AlphaBlendEnable, True)
            xDevice.SetRenderState(RenderState.CullMode, IIf(Flags And 4 = 4, Cull.None, Cull.Counterclockwise))
            SetFramebufferFunction(framebufferBlendFunction)

            xDevice.SetRenderState(RenderState.AlphaTestEnable, (Flags And 1 = 1))

            xDevice.SetRenderState(RenderState.AlphaRef, &H80)
            xDevice.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual)

            For x As Integer = 0 To Maps.Count - 1

                xDevice.SetTexture(x, Maps(x).map)

                If x > 0 Then
                    xDevice.SetTextureStageState(x, TextureStage.ColorOperation, FramebufferFunction(Maps(x - 1).colorFunction, inverseColor))
                    xDevice.SetTextureStageState(x, TextureStage.AlphaOperation, FramebufferFunction(Maps(x - 1).alphaFunction, inverseAlpha))
                End If

                If Maps(x).flags And 2 = 2 Then
                    xDevice.SetTextureStageState(x, TextureStage.ColorArg1, TextureArgument.Texture Or TextureArgument.AlphaReplicate)
                Else
                    xDevice.SetTextureStageState(x, TextureStage.ColorArg1, TextureArgument.Texture)
                End If

                xDevice.SetTextureStageState(x, TextureStage.ColorArg2, TextureArgument.Current)
                xDevice.SetTextureStageState(x, TextureStage.AlphaArg1, TextureArgument.Texture)
                xDevice.SetTextureStageState(x, TextureStage.AlphaArg2, TextureArgument.Current)

                If inverseAlpha Then
                    xDevice.SetTextureStageState(x, TextureStage.AlphaArg0, xDevice.GetTextureStageState(x, TextureStage.AlphaArg2))
                    xDevice.SetTextureStageState(x, TextureStage.AlphaArg2, xDevice.GetTextureStageState(x, TextureStage.AlphaArg1))
                    xDevice.SetTextureStageState(x, TextureStage.AlphaArg1, xDevice.GetTextureStageState(x, TextureStage.AlphaArg0))
                End If
                If inverseColor Then
                    xDevice.SetTextureStageState(x, TextureStage.ColorArg0, xDevice.GetTextureStageState(x, TextureStage.ColorArg2))
                    xDevice.SetTextureStageState(x, TextureStage.ColorArg2, xDevice.GetTextureStageState(x, TextureStage.ColorArg1))
                    xDevice.SetTextureStageState(x, TextureStage.ColorArg1, xDevice.GetTextureStageState(x, TextureStage.ColorArg0))
                End If

                If Maps(x).flags And 1 = 1 Then
                    xDevice.SetSamplerState(x, SamplerState.MinFilter, TextureFilter.None)
                    xDevice.SetSamplerState(x, SamplerState.MagFilter, TextureFilter.None)
                    xDevice.SetSamplerState(x, SamplerState.MipFilter, TextureFilter.None)
                Else
                    xDevice.SetSamplerState(x, SamplerState.MinFilter, TextureFilter.Linear)
                    xDevice.SetSamplerState(x, SamplerState.MagFilter, TextureFilter.Linear)
                    xDevice.SetSamplerState(x, SamplerState.MipFilter, TextureFilter.Linear)
                End If

                If Maps(x).flags And 4 = 4 Then
                    xDevice.SetSamplerState(x, SamplerState.AddressU, TextureAddress.Clamp)
                Else
                    xDevice.SetSamplerState(x, SamplerState.AddressU, TextureAddress.Wrap)
                End If

                If Maps(x).flags And 8 = 8 Then
                    xDevice.SetSamplerState(x, SamplerState.AddressV, TextureAddress.Clamp)
                Else
                    xDevice.SetSamplerState(x, SamplerState.AddressV, TextureAddress.Wrap)
                End If

                Dim mTransform As Matrix = Matrix.Identity
                mTransform.M31 = Maps(x).mapUOffset + Animate(Maps(x).uAnimationFunction, Maps(x).uAnimationPeriod, Maps(x).uAnimationScale)
                mTransform.M32 = Maps(x).mapVOffset + Animate(Maps(x).vAnimationFunction, Maps(x).vAnimationPeriod, Maps(x).vAnimationScale)
                mTransform = Matrix.Multiply(Matrix.Scaling(Maps(x).mapUScale, Maps(x).mapVScale, 1), mTransform)
                xDevice.SetTransform(CType(x + 16, TransformState), mTransform)

                xDevice.SetTextureStageState(x, TextureStage.TextureTransformFlags, TextureTransform.Count2)

                If x = 0 Then
                    If Flags And 8 = 8 Then
                        xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, TextureCoordIndex.CameraSpacePosition)
                    ElseIf firstMapType <> 0 Then
                        xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, TextureCoordIndex.CameraSpaceReflectionVector)
                        xDevice.SetTextureStageState(x, TextureStage.TextureTransformFlags, TextureTransform.Count3)
                    Else
                        xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, 0)
                    End If
                Else
                    xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, 0)
                End If
                xDevice.SetTextureStageState(x, TextureStage.ResultArg, TextureArgument.Current)
            Next
            xDevice.SetTextureStageState(Maps.Count, TextureStage.ColorOperation, TextureOperation.Disable)
            xDevice.SetTextureStageState(Maps.Count, TextureStage.AlphaOperation, TextureOperation.Disable)

            'xDevice.PixelShader = tPixel
            'xDevice.VertexShader = tVertex
        End If
    End Sub

    Public Overloads Sub EndPass() Implements IShader.EndPass
        'shaderEffect.EndPass()
    End Sub
    Public Overloads Function BeginShader(ByVal tLightmap As Texture) As Integer Implements IShader.BeginShader
        'shaderEffect.End()
        'sotrEffect.SetValue("world", xDevice.GetTransform(TransformState.World))
        For x As Integer = 0 To Maps.Count
            'xDevice.SetTextureStageState(x, TextureStage.ColorOperation, TextureOperation.Disable)
            'xDevice.SetTextureStageState(x, TextureStage.AlphaOperation, TextureOperation.Disable)
            'xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, x)
            'xDevice.MultiplyTransform(x, Matrix.Identity)
            'xDevice.SetTexture(x, Nothing)
        Next
        Return 1 ' shaderEffect.Begin(FX.DoNotSaveState)
    End Function
    Public Overloads Sub EndShader() Implements IShader.EndShader
        'shaderEffect.End()
        For x As Integer = 0 To Maps.Count
            'xDevice.SetTextureStageState(x, TextureStage.ColorOperation, TextureOperation.Disable)
            'xDevice.SetTextureStageState(x, TextureStage.AlphaOperation, TextureOperation.Disable)
            'xDevice.SetTextureStageState(x, TextureStage.TexCoordIndex, x)
            'xDevice.MultiplyTransform(x, Matrix.Identity)
            'xDevice.SetTexture(x, Nothing)
        Next

    End Sub
End Class
